''' mbinary
#########################################################################
# File : polynomial.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-19  23:07
# Description:
#########################################################################
'''

#!/bin/python3
# notice that  creating   a class's initialization won't conflict with __call__ method 
# because the former  call class ,and the latter  call instance

# to be implemented

class polynomial:
    pls= []
    n = 0
    def dictize(pl):
        if isinstance(pl,int) or isinstance(pl,float):
            pl = {0:pl}
        if isinstance(pl,polynomial):
            pl = pl.polynomial.copy()
        return pl
    def isZero(n):
        return abs(n)<0.000001
    def __init__(self,s='0 0'):
        polynomial.pls.append(self)
        polynomial.n +=1
        if isinstance(s,polynomial):
            self.polynomial=s.polynomial.copy()
            # don't write like this .**self.polynomial = s.polynomial**,it's ref   
            return
        elif isinstance(s,dict):
            self.polynomial = s.copy()
            return
        s= s.replace(',',' ')
        s= s.replace('x',' ')
        s= s.replace('x^',' ')
        s = s.replace(':',' ')
        s = s.replace('\n',' ')
        s = s.split(' ')
        num = len(s)
        i = 0
        print(s)
        self.polynomial = dict()
        li = [float(i) for i in s]
        while i<num:
            if not polynomial.isZero(li[i]):
                index = li[i+1]
                if index in self.polynomial.keys():
                    self.polynomial[index] += li[i]
                else:self.polynomial[index] = li[i]
            i+=2
        if not self.polynomial:
            self.polynomial = {0:0}
    def __iter__(self):
        return iter(list(self.polynomial.keys()))
    def __getitem__(self,key):
        return self.polynomial[key]
    def __setitem__(self,key,val):
        self.polynomial[key] = val
    def __delitem__(self,k):
        del self.polynomial[k]
    def __add__(self,pl):
        pl = polynomial.dictize(pl)
        rst = self.polynomial.copy()
        for i in pl:
            if i not in rst:
                rst[i] = pl[i]
            else:
                rst[i] += pl[i]
                if polynomial.isZero(rst[i]):
                    del rst[i]
        return polynomial(rst)
    def __iadd__(self,pl):
        pl = polynomial.dictize(pl)
        for i in pl:
            if i not in self:
                self[i] = pl[i]
            else:
                self[i] += pl[i]
                if polynomial.isZero(self[i]):
                    del self[i]
        return self
    def __sub__(self,pl):
        pl = polynomial.dictize(pl)
        tmp = {i:-j for i,j in pl.items()}
        return self + tmp
    def __mul__(self,pl):
        pl = polynomial.dictize(pl)
        dic = dict()
        for i in pl:
            for j in self:
                index= i+j
                if index in dic:
                    dic[index] += pl[i]*self[j]
                else:dic[index] = pl[i]*self[j]
        return polynomial({i:j for i,j in dic.items() if not polynomial.isZero(j)})
    def __imul__(self,pl):
        self = self*pl
        return self
    def __pow__(self,n):
        rst = polynomial({0:1})
        for i in range(n):
            rst*=self.polynomial
        return rst
    def __repr__(self):
        return self.__str__()
    def __str__(self):
        output = ''
        if self.polynomial:
            key = sorted(self.polynomial.keys(),reverse = True)
            num = len(key)
            for j,i in enumerate(key):
                if polynomial.isZero(i):
                    output +='%+g'%self[i]
                    continue
                if not polynomial.isZero(self[i]-1):
                    if not polynomial.isZero(self[i]+1):
                        output +="%+g"%self[i]
                    else:output +='-'
                else:output +='+'
                if not polynomial.isZero(i): output +='x'
                if not polynomial.isZero(i-1):output +='^%g'%i
        
        if output[0] == '+':
            return output[1:]
        return output
    def iterPolynomial(self,s):
        rst = polynomial({0:0})
        for i in self:
            rst += s**int(i)*self[i]
        return rst
    def __call__(self,s):
        if isinstance(s,polynomial):
            return  self.iterPolynomial(s)
        sum = 0
        for i in self:
            sum += self[i] * s**i
        return sum
    def __xor__(self,n):
        tmp = polynomial(self)
        for i in range(n):
            self = self.iterPolynomial(tmp)
        return self
    def save(self):
        polynomial.pls.append(self)
        polynomial.n +=1
    def delPlynomial(self,n):
        return polynomial.pls.pop(n-1)
def menu():
    print('polynomial operations')
    print('1.create')
    print('2.add')
    print('3.sub')
    print('4.iadd')
    print('5.mul')
    print('6.del')
    print('7.display')
    print('8.cal val')
    print('9.polynomial iter')
    print('10.menu')
    print('11.exit')

if __name__ == '__main__':
    pass
